# -*- coding: utf-8 -*-

# Copyright (C) 2017 Intel Corporation.  All rights reserved.
# Copyright (c) WanSheng Intelligent Corp. All rights reserved.

#
# Licensed under the Apache License, Version 2.0 (the "License");
#
import json
import traceback 

from coapthon.client.helperclient import HelperClient
from coapthon import defines
from builtins import str

from wa_edge_iot.internals.parser_ocf import OCFDataParser
from wa_edge_iot.internals.parser_lwm2m import LWM2MDataParser

from wa_edge_iot.model.constants import MediaTypeFormat
from ..framework.singleton import singleton


URL_REFRESHER = "/refresher"
URL_RD = "/rd"
URL_IBROKER="/ibroker"
TIMEOUT_GET=2

class DataMonitorParam(object):
    def __init__(self, 
                 device_id, 
                 resource_uri, 
                 property_name = None,
                 interval=10, 
                 sequence=0, 
                 process=False, 
                 monitor_tag = ""):
        
        assert device_id is None or type(device_id) in [str, str]
        assert type(resource_uri) in [str, str]
        assert type(interval) is int
        assert type(sequence) is int
        assert type(process) is bool

        self.property = property_name
        self.device_id = device_id
        if not resource_uri.startswith('/'):
            resource_uri = '/' + resource_uri
        self.resource_uri = resource_uri
        self.interval = interval
        self.sequence = sequence
        self.process = process
        self.tag = monitor_tag
        self.pub_type = None
        
    def set_publish_info(self, publish_type, address):
        self.pub_type = publish_type
        self.pub_addr = address
        
    def to_json(self):
        
        assert self.pub_type is not None
        
        d = {}
        if self.device_id is not None:
            d['di'] = self.device_id
        if self.property is not None:
            d['property'] = self.property
        if self.tag:
            d['monitor-tag'] = self.tag

        d['ri'] = self.resource_uri
        d['interval'] = self.interval
        d['sequence'] = self.sequence
        d['process'] = self.process
        d['app-id'] = self.app_id
        d['pub-type'] = self.pub_type
        d['pub-addr'] =  self.pub_addr
        
        s = json.dumps(d)
        print("DataMonitorParam string: " + s)
        return s


# DataUtility is not singltone class
# Each instance refers to operations on a specific target server

class DataUtility(object):
    
    def __init__(self, 
                 wagent, 
                 ip,
                 port):
        self.__iagent_mgr = wagent
        self.__ip = ip
        self.__port = port
        self.__parser_map={}

        self.register_parser(MediaTypeFormat.APPLICATION_JSON, OCFDataParser())
        self.register_parser(MediaTypeFormat.APPLICATION_JSON_LWM2M,LWM2MDataParser())

    def register_parser(self, format, parser):
        self.__parser_map[format] = parser


    def get_parser(self, format):
        return self.__parser_map.get(format)
    
    def get(self, url, timeout=TIMEOUT_GET):
        try:
            client = HelperClient(server=(self.__ip, self.__port))
            response = client.get(url, timeout = timeout)
            client.close()
            
            return response

        except Exception as e:
            print(str(e))
            client.close()
            return None


    def post(self, resource_url, format, payload, timeout_secs = TIMEOUT_GET):
        try:
            data = (format, payload)
            client = HelperClient(server=(self.__ip, self.__port))
            response = client.post(resource_url, data, timeout=timeout_secs )  #
            
            client.close()
            return response

            
        except Exception as e:
                print("do_resource_post:" + str(e))
        
        client.close()
        return None
    
    
    def put(self, url, format, payload,  wait_seconds = TIMEOUT_GET):
        try:
            client = HelperClient(server=(self.__ip, self.__port))
            data = (format, payload)
            response = client.put(url, data, timeout=wait_seconds)
            client.close()
            if response is None:
                return  defines.Codes.SERVICE_UNAVAILABLE.number
            else:
                return response.code
        except Exception as e:
            print("do_resource_put: " + url + " ," + str(e))
            return defines.Codes.SERVICE_UNAVAILABLE.number



    def add_data_observer(self, param):
        if not isinstance(param, DataMonitorParam):
            raise Exception('param is not instance of class DataMonitorParam')
        
        param.app_id = self.__iagent_mgr.app_id()
        
        if param.tag or param.process or self.__iagent_mgr.redis_util() is None:
            publish_uri = "coap://127.0.0.1:" + str(self.__iagent_mgr.listen_port()) + "/dm"
            param.set_publish_info("coap", publish_uri)
        else:
            param.set_publish_info("redis", "")
            
        try:
            client = HelperClient(server=(self.__ip, self.__port))
            response = client.post(
                URL_REFRESHER,
                param.to_json(),
                timeout=TIMEOUT_GET)  
    
            if response is None:
                print("add_data_observer: no response")
            elif response.code == defines.Codes.CREATED.number or response.code == defines.Codes.CHANGED.number:
                monitor_id = str(response.payload)
                print("add_data_observer returned id: " + monitor_id)
                client.close()
                
                return monitor_id
            else:
                print("add_data_observer: return " + str(response.code))
                
        except Exception as e:
            import traceback
            print("add_data_observer exception: " +  str(e))
            traceback.print_exc()
          
        client.close()
        return None

    def remove_data_observer(self, observer_point_id):
        try:
            client = HelperClient(server=(self.__ip, self.__port))
            response = client.delete(
                URL_REFRESHER + "?id=" + observer_point_id, 
                timeout=TIMEOUT_GET)
            
            if response is None:
                print("remove_data_observer: no response")
            elif response.code ==  defines.Codes.DELETED.number:
                print("remove data listener now!")
                client.close()
                return True
            else:
                print("response code=" + str(response.code))
        except Exception as e:
            print("remove_data_observer exception: " + str(e))
            traceback.print_exc()
            
        client.close()
        return False
